namespace SubSonic
{
    using SubSonic.CodeGenerator;
    using SubSonic.Sugar;
    using SubSonic.Utilities;
    using System;
    using System.CodeDom;
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.IO;

    public static class CodeService
    {
        private static string templateDirectory = string.Empty;

        public static TurboTemplate BuildClassTemplate(string tableName, ICodeLanguage language, DataProvider provider)
        {
            DataService.LoadProviders();
            if (ShouldGenerate(tableName, provider.Name))
            {
                List<Replacement> settings = new List<Replacement>();
                settings.Add(new Replacement(ReplacementVariable.Table, tableName));
                settings.Add(new Replacement(ReplacementVariable.Provider, provider.Name));
                return PrepareTemplate("Class - " + provider.Name + ": " + tableName, TemplateType.Class, settings, language, provider);
            }
            Utility.WriteTrace("Class " + tableName + " is excluded from generation");
            return null;
        }

        public static CodeCompileUnit BuildCompilUnit(string code)
        {
            return new CodeSnippetCompileUnit(code);
        }

        public static TurboTemplate BuildODSTemplate(string tableName, ICodeLanguage language, DataProvider provider)
        {
            DataService.LoadProviders();
            if (ShouldGenerate(tableName, provider.Name) && provider.GenerateODSControllers)
            {
                List<Replacement> settings = new List<Replacement>();
                settings.Add(new Replacement(ReplacementVariable.Table, tableName));
                settings.Add(new Replacement(ReplacementVariable.Provider, provider.Name));
                return PrepareTemplate("ODS Controller - " + provider.Name + ": " + tableName, TemplateType.ODSController, settings, language, provider);
            }
            Utility.WriteTrace(tableName + " is Excluded from generation");
            return null;
        }

        public static TurboTemplate BuildSPTemplate(ICodeLanguage language, DataProvider provider)
        {
            DataService.LoadProviders();
            List<Replacement> settings = new List<Replacement>();
            settings.Add(new Replacement(ReplacementVariable.Provider, provider.Name));
            return PrepareTemplate("Stored Procedure Class - " + provider.Name, TemplateType.SP, settings, language, provider);
        }

        public static TurboTemplate BuildStructsTemplate(ICodeLanguage language, DataProvider provider)
        {
            DataService.LoadProviders();
            List<Replacement> settings = new List<Replacement>();
            return PrepareTemplate("Structs Class", TemplateType.Structs, settings, language, provider);
        }

        public static TurboTemplate BuildTemplate(TemplateType templateType, NameValueCollection values, ICodeLanguage language, DataProvider provider)
        {
            string templateText = GetTemplateText(templateType, language);
            for (int i = 0; i < values.Count; i++)
            {
                templateText = templateText.Replace(values.GetKey(i), values.Get(i));
            }
            return new TurboTemplate(templateText, language, provider);
        }

        public static TurboTemplate BuildViewTemplate(string tableName, ICodeLanguage language, DataProvider provider)
        {
            DataService.LoadProviders();
            if (ShouldGenerate(tableName, provider.Name))
            {
                List<Replacement> settings = new List<Replacement>();
                settings.Add(new Replacement(ReplacementVariable.View, tableName));
                settings.Add(new Replacement(ReplacementVariable.Provider, provider.Name));
                return PrepareTemplate("View - " + provider.Name + ": " + tableName, TemplateType.ReadOnly, settings, language, provider);
            }
            Utility.WriteTrace("View " + tableName + " is excluded from generation");
            return null;
        }

        private static string GetTemplateText(TemplateType t, ICodeLanguage language)
        {
            string templatePrefix = language.TemplatePrefix;
            string fileText = null;
            switch (t)
            {
                case TemplateType.Class:
                    templatePrefix = templatePrefix + "ClassTemplate";
                    break;

                case TemplateType.ODSController:
                    templatePrefix = templatePrefix + "ODSController";
                    break;

                case TemplateType.ReadOnly:
                    templatePrefix = templatePrefix + "ViewTemplate";
                    break;

                case TemplateType.SP:
                    templatePrefix = templatePrefix + "SPTemplate";
                    break;

                case TemplateType.Structs:
                    templatePrefix = templatePrefix + "StructsTemplate";
                    break;

                case TemplateType.DynamicScaffold:
                    templatePrefix = templatePrefix + "DynamicScaffold";
                    break;

                case TemplateType.GeneratedScaffoldCodeBehind:
                    templatePrefix = templatePrefix + "GeneratedScaffoldCodeBehind";
                    break;

                case TemplateType.GeneratedScaffoldMarkup:
                    templatePrefix = templatePrefix + "GeneratedScaffoldMarkup";
                    break;

                default:
                    templatePrefix = templatePrefix + "ClassTemplate";
                    break;
            }
            templatePrefix = templatePrefix + ".aspx";
            if (!string.IsNullOrEmpty(templateDirectory))
            {
                Utility.WriteTrace("Looking for template " + templatePrefix + " in " + templateDirectory);
                string path = Path.Combine(templateDirectory, templatePrefix);
                if (File.Exists(path))
                {
                    fileText = Files.GetFileText(path);
                }
                else
                {
                    Utility.WriteTrace("Template " + templatePrefix + " NOT FOUND in directory " + templateDirectory + "; using embedded resource template instead...");
                }
            }
            if (string.IsNullOrEmpty(fileText))
            {
                Utility.WriteTrace("Loading template from resource: " + templatePrefix);
                fileText = TurboTemplate.LoadTextFromManifest(templatePrefix);
            }
            if (string.IsNullOrEmpty(fileText))
            {
                throw new Exception("The template \"" + templatePrefix + "\" is empty or cannot be found.");
            }
            return fileText;
        }

        private static TurboTemplate PrepareTemplate(string templateName, TemplateType templateType, IEnumerable<Replacement> settings, ICodeLanguage language, DataProvider provider)
        {
            Utility.WriteTrace("Getting template for " + templateName);
            string templateText = GetTemplateText(templateType, language);
            Utility.WriteTrace("Preparing template for " + templateName);
            foreach (Replacement replacement in settings)
            {
                string pattern = "#" + Enum.GetName(typeof(ReplacementVariable), replacement.Variable).ToUpper() + "#";
                templateText = Utility.FastReplace(templateText, pattern, replacement.ReplaceWith, StringComparison.InvariantCultureIgnoreCase);
            }
            TurboTemplate template = new TurboTemplate(templateText, language, provider);
            template.TemplateName = templateName;
            return template;
        }

        public static string RunClass(string tableName, ICodeLanguage language, DataProvider provider)
        {
            return BuildClassTemplate(tableName, language, provider).Render();
        }

        public static string RunODS(string tableName, ICodeLanguage language, DataProvider provider)
        {
            return BuildODSTemplate(tableName, language, provider).Render();
        }

        public static string RunReadOnly(string viewName, ICodeLanguage language, DataProvider provider)
        {
            return BuildViewTemplate(viewName, language, provider).Render();
        }

        public static string RunSPs(ICodeLanguage language, DataProvider provider)
        {
            return BuildSPTemplate(language, provider).Render();
        }

        public static string RunStructs(ICodeLanguage language, DataProvider provider)
        {
            return BuildStructsTemplate(language, provider).Render();
        }

        public static string RunTemplate(TemplateType templateType, IEnumerable<Replacement> settings, ICodeLanguage language, DataProvider provider)
        {
            Utility.WriteTrace("Getting Template");
            string templateText = GetTemplateText(templateType, language);
            Utility.WriteTrace("Replacing values in template");
            foreach (Replacement replacement in settings)
            {
                string pattern = "#" + Enum.GetName(typeof(ReplacementVariable), replacement.Variable).ToUpper() + "#";
                templateText = Utility.FastReplace(templateText, pattern, replacement.ReplaceWith, StringComparison.InvariantCultureIgnoreCase);
            }
            TurboTemplate template = new TurboTemplate(templateText, language, provider);
            Utility.WriteTrace("Rendering template");
            string str3 = template.Render();
            Utility.WriteTrace("Finished :)");
            return str3;
        }

        public static string RunTemplate(string templateFile, NameValueCollection values, ICodeLanguage language, DataProvider provider)
        {
            string fileText = Files.GetFileText(Path.Combine(TemplateDirectory, templateFile));
            for (int i = 0; i < values.Count; i++)
            {
                fileText = fileText.Replace(values.GetKey(i), values.Get(i));
            }
            TurboTemplate template = new TurboTemplate(fileText, language, provider);
            return template.Render();
        }

        public static bool ShouldGenerate(TableSchema.Table tbl)
        {
            return ShouldGenerate(tbl.TableName, tbl.Provider.Name);
        }

        public static bool ShouldGenerate(string tableName, string providerName)
        {
            DataProvider provider = DataService.Providers[providerName];
            if (provider == null)
            {
                throw new Exception("There is no provider with the name " + providerName);
            }
            return ShouldGenerate(tableName, provider.IncludeTables, provider.ExcludeTables, provider);
        }

        public static bool ShouldGenerate(string objectName, string[] includeList, string[] excludeList, DataProvider provider)
        {
            bool flag = true;
            bool flag2 = false;
            if ((includeList.Length == 1) && (includeList[0] == "*"))
            {
                flag2 = true;
            }
            if (flag2)
            {
                foreach (string str in excludeList)
                {
                    if (Utility.IsRegexMatch(objectName, str.Trim()))
                    {
                        return false;
                    }
                }
                return flag;
            }
            flag = false;
            foreach (string str2 in includeList)
            {
                if (Utility.IsMatch(objectName, str2.Trim()))
                {
                    return true;
                }
            }
            return flag;
        }

        public static string TemplateDirectory
        {
            get
            {
                return templateDirectory;
            }
            set
            {
                templateDirectory = value;
            }
        }

        public class Replacement
        {
            private CodeService.ReplacementVariable replaceVar;
            private string replaceWith;

            public Replacement(CodeService.ReplacementVariable variable, string replace)
            {
                this.Variable = variable;
                this.ReplaceWith = replace;
            }

            public string ReplaceWith
            {
                get
                {
                    return this.replaceWith;
                }
                set
                {
                    this.replaceWith = value;
                }
            }

            public CodeService.ReplacementVariable Variable
            {
                get
                {
                    return this.replaceVar;
                }
                set
                {
                    this.replaceVar = value;
                }
            }
        }

        public enum ReplacementVariable
        {
            Table,
            Provider,
            View,
            StoredProcedure
        }

        public enum TemplateType
        {
            Class,
            ODSController,
            ReadOnly,
            SP,
            Structs,
            DynamicScaffold,
            GeneratedScaffoldCodeBehind,
            GeneratedScaffoldMarkup
        }
    }
}

